package com.sky.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;


/**
 *   封装 HttpClient的工具类
 *   用来发送get/post请求的
 *                              尽量解耦合，少用第三方工具jar，减少本工具类迁移成本
 */
public class HttpClientUtil {

    //连接超时时间(单位毫秒)
    private static final int CONNECT_TIMEOUT = 7000;
    //从连接池获取http请求对象的超时时间(单位毫秒)  没有连接池则不用设置
    private static final int CONNECTION_REQUEST_TIMEOUT = 7000;
    //读取超时，表示从请求的网址处获得响应数据的时间间隔(单位毫秒)
    private static final int SOCKET_TIMEOUT = 7000;

    // 请求的一些配置  公共使用，如果请求需要特殊设置，请在方法中自定义
    private static RequestConfig requestConfig = RequestConfig.custom()
            //设置连接超时时间(单位毫秒) ，3次握手
            .setConnectTimeout(CONNECT_TIMEOUT)
            //从连接池获取http请求对象的超时时间(单位毫秒)
            //.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
            //读取超时，表示从请求的网址处获得响应数据的时间间隔(单位毫秒)
            .setSocketTimeout(SOCKET_TIMEOUT)
            //设置是否允许重定向(默认为true)
            .setRedirectsEnabled(true)
            .build();


    //本地文件存储路径
    @Value("${file.path}")
    private static String filePath;




    /**
     * Get请求                     get请求没有Content-Type
     * 无参 或者为 /{param}路径参数   响应的回来的json数据
     */
    public static String doGetNoParamsAndResponseJson(String url) {

        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Get请求对象
        HttpGet httpGet = new HttpGet(url);

        // 3.设置请求的一些配置
        httpGet.setConfig(requestConfig);
        //添加请求头
        // token
        httpGet.addHeader("token", "Bearer xxxxxxxxx");
        // http被认为不是真人通过浏览器访问
        //httpGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpGet.addHeader("Referer", "https://www.baidu.com/");

        //响应对象
        CloseableHttpResponse response = null;

        try {
            // 4.发送请求
            response = httpClient.execute(httpGet);

            // 5.解析数据
            int statusCode = response.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK == statusCode) {
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                System.out.println(url + "--get请求(无参)--接口返回错误信息: " + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                //EntityUtils.consume(response.getEntity());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " -- response响应关闭失败......");
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " -- httpClient关闭失败......");
                }
            }
        }

        return resultStr;
    }



    /**
     * Get请求                     get请求没有Content-Type
     * 无参 或者为 /{param}路径参数   响应的回来的File文件
     *
     */
    public static void doGetNoParamsAndResponseIOFile(String url) {

        // 1.创建HttpClient对象，类似于浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Get请求对象
        HttpGet httpGet = new HttpGet(url);

        // 3.设置请求的一些配置
        httpGet.setConfig(requestConfig);
        //添加请求头
        // token
        //httpGet.addHeader("token", "Bearer xxxxxxxxx");

        //响应对象
        CloseableHttpResponse response = null;
        //写入本地输出流
        BufferedOutputStream bos = null;
        //写入本地的文件路径
        String fileAbsPath = null;

        try {
            // 4.发送请求
            response = httpClient.execute(httpGet);

            // 5.解析数据
            if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
                HttpEntity entity = response.getEntity();
                // 获取文件返回的类型  文件后缀名
                String contentType = entity.getContentType().getValue();
                String suffixStr = contentType.substring(contentType.lastIndexOf("/") + 1);
                if(suffixStr.contains(";")){
                    suffixStr = suffixStr.substring(0, suffixStr.lastIndexOf(";"));
                }

                //文件名
                String fileName = UUID.randomUUID().toString().replace("-", "") + "." + suffixStr;

                //返回数据解析为byte[]字节数组
                byte[] bytes = EntityUtils.toByteArray(entity);

                // 保存路径 文件夹是否存在
                File file = new File(filePath);
                if( !file.exists() ){
                    file.mkdirs();
                }

                //文件全路径名
                fileAbsPath= filePath + File.separator + fileName;
                System.out.println(fileAbsPath);

                //创建输出IO流
                bos = new BufferedOutputStream(new FileOutputStream(fileAbsPath));
                bos.write(bytes);
                bos.flush();
            } else {
                System.out.println(url + " --请求File文件返回状态码:code==> " + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(null != bos){
                try {
                    bos.close();
                } catch (IOException e) {
                    System.out.println(fileAbsPath + " --写入本地关流失败");
                }
            }
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " --响应response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " --请求客户端关闭失败");
                }
            }
        }

    }



    /**
     * Get请求 -- 带参数   响应的回来的json数据
     *
     */
    public static String doGetHasParamsResponseJson(String url, Map<String, String> paramsMap){

        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //响应对象
        CloseableHttpResponse response = null;

        try {
            // 2.创建URIBuilder对象，设置请求url和参数  参数最好进行utf-8编码
            URIBuilder builder = new URIBuilder(url);
            // 设置参数
            if( !CollectionUtils.isEmpty(paramsMap) ){
                for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
                    //像浏览器一样对value进行编码 --> URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString())
                    builder.addParameter(entry.getKey(), entry.getValue());
                }
            }
            // 封装完毕，构建uri
            URI uri = builder.build();

            // 3.创建Get请求对象
            HttpGet httpGet = new HttpGet(uri);

            // 4.设置请求的一些配置
            httpGet.setConfig(requestConfig);
            //请求头 token、防盗链 等
            httpGet.addHeader("token", "Bearer xxxxxx");

            // 5.执行带参的Get请求
            response = httpClient.execute(httpGet);

            // 6.解析
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                System.out.println(url + "--get请求(有参)--接口返回错误信息: " + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
                //EntityUtils.consume(response.getEntity());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " -- response响应关闭失败......");
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " -- httpClient关闭失败......");
                }
            }
        }

        return resultStr;
    }



    /**
     * Get请求 -- 带参数   响应的回来的File文件
     *
     */
    public static void doGetHasParamsResponseIOFile(String url,Map<String, String> paramsMap){

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //响应对象
        CloseableHttpResponse response = null;
        //写入本地输出流
        BufferedOutputStream bos = null;
        //写入本地的文件路径
        String fileAbsPath = null;

        try {
            // 2.创建URIBuilder对象，设置请求url和参数  参数最好进行utf-8编码
            URIBuilder builder = new URIBuilder(url);
            // 设置参数
            if( !CollectionUtils.isEmpty(paramsMap) ){
                for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
                    //像浏览器一样对value进行编码 --> URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.toString())
                    builder.addParameter(entry.getKey(), entry.getValue());
                }
            }
            // 封装完毕，构建uri
            URI uri = builder.build();

            // 3.创建Get请求对象
            HttpGet httpGet = new HttpGet(uri);

            // 4.设置请求的一些配置
            httpGet.setConfig(requestConfig);
            //请求头 token、防盗链 等
            httpGet.addHeader("token", "Bearer xxxxxx");

            // 5.执行带参的Get请求
            response = httpClient.execute(httpGet);

            // 6.解析
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                // 获取文件后缀名
                String contentType = entity.getContentType().getValue();
                String suffixStr = contentType.substring(contentType.lastIndexOf("/") + 1);
                if(suffixStr.contains(";")){
                    suffixStr = suffixStr.substring(0, suffixStr.lastIndexOf(";"));
                }

                // 文件名
                String fileName = UUID.randomUUID().toString().replace("-", "") + "." + suffixStr;

                // 7.返回数据解析为byte[]数组
                byte[] bytes = EntityUtils.toByteArray(entity);

                //存储文件路径 是否存在
                File file = new File(filePath);
                if( !file.exists() ){
                    file.mkdirs();
                }

                //文件全路径名  如果要加日期文件夹 --> Windows:"\\"   Linux:"/"
                fileAbsPath = filePath + File.separator + fileName;

                // 创建输出流
                bos = new BufferedOutputStream(new FileOutputStream(fileAbsPath));
                bos.write(bytes, 0, bytes.length);
                bos.flush();
            } else {
                System.out.println(url + " --请求File文件返回状态码:code==> " + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if(null != bos){
                try {
                    bos.close();
                } catch (IOException e) {
                    System.out.println(fileAbsPath + " --写入本地关流失败");
                }
            }
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " --响应response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " --请求客户端关闭失败");
                }
            }
        }

    }



    /**
     * Post请求 -- 无参   响应的回来的Json数据
     * @param url
     */
    public static String doPostNoParamsResponseJson(String url){

        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.设置请求的一些配置
        httpPost.setConfig(requestConfig);
        //添加请求头
        httpPost.addHeader("token", "Bearer xxxxxxxxx");
        // http被认为不是真人通过浏览器访问
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");

        //响应对象
        CloseableHttpResponse response = null;

        try {
            // 4.执行post请求
            response = httpClient.execute(httpPost);

            // 5.解析
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                System.out.println(url + "--post请求(无参)--接口返回错误信息: " + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " -- response响应关闭失败......");
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " -- httpClient关闭失败......");
                }
            }
        }

        return resultStr;
    }



    /**
     * Post请求 -- 无参  响应的回来的File文件
     * @param url
     */
    public static void doPostNoParamsResponseIOFile(String url){

        // 1.创建HttpClientD对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.设置请求的一些配置
        httpPost.setConfig(requestConfig);
        //添加请求头
        // token
        httpPost.addHeader("token", "Bearer xxxxxxxxx");
        // http被认为不是真人通过浏览器访问
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");

        //响应
        CloseableHttpResponse response = null;
        //写入本地输出流
        BufferedOutputStream bos = null;
        //写入本地的文件路径
        String fileAbsPath = null;

        try {
            // 4.执行请求
            response = httpClient.execute(httpPost);

            // 5.解析数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                // 获取文件后缀名
                String contentType = entity.getContentType().getValue();
                String suffixStr = contentType.substring(contentType.lastIndexOf("/") + 1);
                if(suffixStr.contains(";")){
                    suffixStr = suffixStr.substring(0, suffixStr.lastIndexOf(";"));
                }

                // 文件名
                String fileName = UUID.randomUUID().toString().replace("-", "") + "." + suffixStr;

                // 返回的数据解析为byte[]数组
                byte[] bytes = EntityUtils.toByteArray(entity);

                //存储文件夹 是否存在
                File file = new File(filePath);
                if( !file.exists() ){
                    file.mkdirs();
                }

                // 文件全路径名
                fileAbsPath = filePath + File.separator + fileName;

                // 创建写出流
                bos = new BufferedOutputStream(new FileOutputStream(fileAbsPath));
                bos.write(bytes, 0, bytes.length);
                bos.flush();
            } else {
                System.out.println(url + " --请求File文件返回状态码code:==> " + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(null != bos){
                try {
                    bos.close();
                } catch (IOException e) {
                    System.out.println(fileAbsPath + " --写入本地关流失败");
                }
            }
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " --响应response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " --请求客户端关闭失败");
                }
            }
        }

    }



    /**
     * Post请求 -- 有参   响应回来的Json数据    application/x-www-form-urlencoded
     */
    public static String doPostSimpleFormHasParamsResponseJson(String url, Map<String, String> paramMap){

        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 添加请求头  application/x-www-form-urlencoded
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");

        // 3.Post请求的一些配置
        httpPost.setConfig(requestConfig);
        //添加请求头
        httpPost.addHeader("token", "Bearer xxxxxxxxx");
        // http被认为不是真人通过浏览器访问
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");

        // 4.封装入参body数据
        /**
         * NameValuePair: 相当于前端<input>标签  有name属性以及输入的具体值
         */
        List<NameValuePair> inputList = new ArrayList<>();
        if( !CollectionUtils.isEmpty(paramMap) ){
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                //  BasicNameValuePair实现了 NameValuePair接口
                inputList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }

        // 5.创建表单对象  设置字符集编码
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(inputList, StandardCharsets.UTF_8);

        // 6.将表单参数设置到Post请求对象中
        httpPost.setEntity(formEntity);


        //响应对象
        CloseableHttpResponse response = null;

        try {
            // 7.执行请求
            response = httpClient.execute(httpPost);

            // 8.解析数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
            } else {
                System.out.println(url + "--[x-www-form-urlencoded]-post请求(有参)--接口返回错误信息:" + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " -- response响应关闭失败......");
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " -- httpClient关闭失败......");
                }
            }
        }

        return resultStr;
    }



    /**
     * Post请求 -- 有参   响应回来的File文件    application/x-www-form-urlencoded
     * @param url
     * @param paramMap
     */
    public static void doPostSimpleFormHasParamsResponseIOFile(String url, Map<String, String> paramMap){

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 添加请求头  application/x-www-form-urlencoded
        httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");

        // 3.Post请求的一些配置
        httpPost.setConfig(requestConfig);

        //添加请求头
        httpPost.addHeader("token", "Bearer xxxxxxxxx");
        // http被认为不是真人通过浏览器访问
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");

        // 4.封装入参body数据
        /**
         * NameValuePair: 相当于前端<input>标签  有name属性以及输入的具体值
         */
        List<NameValuePair> inputList = new ArrayList<>();
        if( !CollectionUtils.isEmpty(paramMap) ){
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                //  BasicNameValuePair实现了 NameValuePair接口
                inputList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
            }
        }

        // 5.创建表单对象  设置字符集
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(inputList, StandardCharsets.UTF_8);
        // 6.设置表单数据到post请求对象中
        httpPost.setEntity(formEntity);


        //响应
        CloseableHttpResponse response = null;
        //写入本地输出流
        BufferedOutputStream bos = null;
        //写入本地的文件路径
        String fileAbsPath = null;

        try {
            // 7.执行请求
            response = httpClient.execute(httpPost);

            // 8.解析数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                // 获取文件后缀名
                String contentType = entity.getContentType().getValue();
                String suffixStr = contentType.substring(contentType.lastIndexOf("/") + 1);
                if(suffixStr.contains(";")){
                    suffixStr = suffixStr.substring(0, suffixStr.lastIndexOf(";"));
                }

                // 文件名
                String fileName = UUID.randomUUID().toString().replace("-","") + "." + suffixStr;

                // 返回数据解析为byte[]数组
                byte[] bytes = EntityUtils.toByteArray(entity);

                // 存储文件夹  是否存在
                File file = new File(filePath);
                if( !file.exists() ){
                    file.mkdirs();
                }

                // 文件全名
                fileAbsPath = filePath + File.separator + fileName;

                // 创建输出流
                bos = new BufferedOutputStream(new FileOutputStream(fileAbsPath));
                bos.write(bytes, 0, bytes.length);
                bos.flush();
            } else {
                System.out.println(url + " --请求File文件返回状态码:code ==> " + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(null != bos){
                try {
                    bos.close();
                } catch (IOException e) {
                    System.out.println(fileAbsPath + " --写入本地关流失败");
                }
            }
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " --响应response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " --请求客户端关闭失败");
                }
            }
        }

    }



    /**
     * Post请求  -- 有参   响应回来的Json数据     multipart/form-data 涉及file文件上传
     * @param url
     * @param fileParamName
     * @param file
     * @param paramMap
     */
    public static String doPostFormDataHasParamsResponseJson(String url, String fileParamName, MultipartFile file, Map<String, String> paramMap){

        String resultStr = null;

        // 1.创建HttpClient对像，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.设置请求的一些配置
        httpPost.setConfig(requestConfig);

        //设置请求头
        httpPost.addHeader("Content-Type", "multipart/form-data; charset=UTF-8");
        //token
        httpPost.addHeader("token", "Bearer eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNjk1NjUyMDA1fQ.L7gw2eL_mxaplCBC0aU6VieRIDHMsdXHrt1081l4evw");
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");

        // 4.构造File文件上传使用的entity
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        // 5.设置请求的类型
        builder.setContentType(ContentType.create("multipart/form-data", Consts.UTF_8));
        // 6.设置编码
        builder.setCharset(Consts.UTF_8);
        // 7.设置为 浏览器上传模式(解决返回中文乱码问题)
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

        // 8.封装file文件IO流参数
        try {                //   单个或数组名     file的IO                文件类型                                                              文件名
            builder.addBinaryBody(fileParamName, file.getInputStream(), ContentType.create("multipart/form-data", Consts.UTF_8), file.getOriginalFilename());
        } catch (IOException e) {
            System.out.println(url + "--post(有参)请求--[form-data]--封装File文件参数异常");
            e.printStackTrace();
        }

        // 9.添加表单中<input>标签的字段值    类似浏览器表单提交，对应input的name和value
        if( !CollectionUtils.isEmpty(paramMap) ){
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                // addTextBody(k, v) ---> v是中文则乱码 -->  addTextBody(k, v, ContentType.create("text/plain", HTTP.UTF_8))
                builder.addPart(entry.getKey(), new StringBody(entry.getValue(), ContentType.create(HTTP.PLAIN_TEXT_TYPE, Consts.UTF_8)));
            }
        }

        // 10.构建httpEntity参数对象
        HttpEntity httpEntity = builder.build();
        // 11.设置参数到post请求对象中
        httpPost.setEntity(httpEntity);

        //响应对象
        CloseableHttpResponse response = null;

        try {
            // 12.执行post请求
            response = httpClient.execute(httpPost);

            // 13.解析数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                System.out.println(resultStr);

                //转为JSONObject
                JSONObject jsonObject = JSONObject.parseObject(resultStr);
                System.out.println(jsonObject);

            } else {
                System.out.println(url + "--[form-data]-post请求(有参)--接口返回错误信息:" + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != response) {
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " -- response响应关闭失败......");
                }
            }
            if (null != httpClient) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " -- httpClient关闭失败......");
                }
            }
        }

        return resultStr;
    }



    /**
     * Post请求  -- 有参   响应回来的File文件     application/form-data   涉及file文件上传
     * @param url
     * @param fileParamName
     * @param file
     * @param paramMap
     */
    public static void doPostFormDataHasParamsResponseFile(String url, String fileParamName, MultipartFile file, Map<String, String> paramMap){

        // 1.创建HttpClient对象。类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建Post对象
        HttpPost httpPost = new HttpPost(url);

        // 3.请求的一些配置
        httpPost.setConfig(requestConfig);
        // 添加请求头
        httpPost.addHeader("token", "Bearer eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNjk1NjUyMDA1fQ.L7gw2eL_mxaplCBC0aU6VieRIDHMsdXHrt1081l4evw");
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");

        // 4.构造上传File文件的Entity
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        // 5.设置请求类型
        builder.setContentType(ContentType.create("multipart/form-data", Consts.UTF_8));
        // 6.设置编码
        builder.setCharset(Consts.UTF_8);
        // 7.设置为 浏览器上传模式(解决返回中文乱码问题)
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

        // 8.封装File文件IO流参数
        try {
            builder.addBinaryBody(fileParamName, file.getInputStream(), ContentType.create("multipart/form-data", Consts.UTF_8), file.getOriginalFilename());
        } catch (IOException e) {
            System.out.println(url + " --post(有参)请求--[form-data]--封装File文件参数异常");
            e.printStackTrace();
        }

        // 9.添加表单中<input>标签的字段值    类似浏览器表单提交，对应input的name和value
        if( !CollectionUtils.isEmpty(paramMap) ){
            for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                // addTextBody(k, v) ---> v是中文则乱码 -->  addTextBody(k, v, ContentType.create("text/plain", HTTP.UTF_8))
                builder.addPart(entry.getKey(), new StringBody(entry.getValue(), ContentType.create(HTTP.PLAIN_TEXT_TYPE, Consts.UTF_8)));
            }
        }

        // 10.构建httpEntity参数对象
        HttpEntity httpEntity = builder.build();

        // 11.设置参数到post请求中
        httpPost.setEntity(httpEntity);

        //响应对象
        CloseableHttpResponse response = null;
        // 输出流
        BufferedOutputStream bos = null;
        // 文件全路径名
        String fileAbsPath = null;

        try {
            // 12.执行请求
            response = httpClient.execute(httpPost);

            // 13.解析数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                // 获取返回的文件后缀名
                String contentType = entity.getContentType().getValue();  //  举例: application/json; charset=utf-8
                String suffixStr = contentType.substring(contentType.lastIndexOf("/") + 1);
                if(suffixStr.contains(";")){
                    suffixStr = suffixStr.substring(0, suffixStr.lastIndexOf(";"));
                }

                // 文件名
                String fileName = UUID.randomUUID().toString().replace("-", "") + "." + suffixStr;

                // 返回的数据解析为byte[]数组
                byte[] bytes = EntityUtils.toByteArray(entity);

                // 存储文件夹 是否存在
                File files = new File(filePath);
                if( !files.exists() ){
                    files.mkdirs();
                }

                // 文件全路径名
                fileAbsPath = filePath + File.separator + fileName;

                // 创建文件输出流 写出
                bos = new BufferedOutputStream(new FileOutputStream(fileAbsPath));
                bos.write(bytes, 0, bytes.length);
                bos.flush();
            } else {
                System.out.println(url + " --请求File文件返回状态码:code==> " + response.getStatusLine().getStatusCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(null != bos){
                try {
                    bos.close();
                } catch (IOException e) {
                    System.out.println(fileAbsPath + " --写入本地关流失败");
                }
            }
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " --响应response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " --请求客户端关闭失败");
                }
            }
        }

    }



    /**
     * post请求  --  有参  返回的json数据   application/json
     * @param url
     * @param paramMap
     */
    public static String doPostJsonHasParamsResponseJson(String url, Map<String, String> paramMap){

        String resultStr = null;

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.请求的一些配置
        httpPost.setConfig(requestConfig);
        // 添加请求头
        httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
        //token
        httpPost.addHeader("token", "Bearer eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNjk1NjUyMDA1fQ.L7gw2eL_mxaplCBC0aU6VieRIDHMsdXHrt1081l4evw");
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");


        if ( !CollectionUtils.isEmpty(paramMap) ){
            // 4.构建封装json参数的Entity    并设置 编码
            StringEntity httpEntity = new StringEntity(JSON.toJSONString(paramMap, SerializerFeature.WriteMapNullValue), Consts.UTF_8);
            // 5.设置请求方式
            httpEntity.setContentType("application/json; charset=utf-8");
            // 6.设置编码
            httpEntity.setContentEncoding(Consts.UTF_8.toString());
            // 7.将封装json参数的entity设置到post请求对象中
            httpPost.setEntity(httpEntity);
        }

        // 响应对象
        CloseableHttpResponse response = null;

        try {
            // 8.执行请求
            response = httpClient.execute(httpPost);

            // 9.解析
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                resultStr = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                System.out.println(resultStr);

                //转为JSONObject
                JSONObject jsonObject = JSONObject.parseObject(resultStr);
                System.out.println(jsonObject);

            } else {
                System.out.println(url + "--[json]-post请求(有参)--接口返回错误信息:" + EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
                resultStr =  EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
            }
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + "--response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + "--httpClient关闭失败");
                }
            }
        }

        return resultStr;
    }



    /**
     * post请求  -- 有参  返回的File文件   application/json
     * @param url
     * @param paramMap
     */
    public static void doPostJsonHasParamsResponseIOFile(String url, Map<String, String> paramMap){

        // 1.创建HttpClient对象，类似于浏览器(不是浏览器)
        CloseableHttpClient httpClient = HttpClients.createDefault();

        // 2.创建post请求对象
        HttpPost httpPost = new HttpPost(url);

        // 3.请求的一些配置
        httpPost.setConfig(requestConfig);
        // 添加请求头
        httpPost.addHeader("token", "Bearer eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNjk1NjUyMDA1fQ.L7gw2eL_mxaplCBC0aU6VieRIDHMsdXHrt1081l4evw");
        //httpPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36");
        // value: 爬取图片，需要从本网页访问图片，才能下载 --> 发生防盗链网站的url
        //httpPost.addHeader("Referer", "https://www.baidu.com/");


        if( !CollectionUtils.isEmpty(paramMap) ){
            // 4.构建封装json参数的Entity    并设置 编码
            StringEntity httpEntity = new StringEntity(JSON.toJSONString(paramMap), Consts.UTF_8);
            // 5.设置请求方式
            httpEntity.setContentType("application/json");
            // 6.设置编码
            httpEntity.setContentEncoding(Consts.UTF_8.toString());
            // 7.将封装json参数的entity设置到post请求对象中
            httpPost.setEntity(httpEntity);
        }

        //响应
        CloseableHttpResponse response = null;
        //写入本地输出流
        BufferedOutputStream bos = null;
        //写入本地的文件路径
        String fileAbsPath = null;

        try {
            // 8.执行请求
            response = httpClient.execute(httpPost);

            // 9.解析数据
            if(HttpStatus.SC_OK == response.getStatusLine().getStatusCode()){
                HttpEntity entity = response.getEntity();
                // 10.获取文件后缀名
                String contentType = entity.getContentType().getValue();        // application/json; charset=utf-8
                String suffixStr = contentType.substring(contentType.lastIndexOf("/") + 1);
                if(suffixStr.contains(";")){
                    suffixStr = suffixStr.substring(0, suffixStr.lastIndexOf(";"));
                }

                // 11.文件名
                String fileName = UUID.randomUUID().toString().replace("-", "") + "." + suffixStr;

                // 12.返回的数据解析为byte[]数组
                byte[] bytes = EntityUtils.toByteArray(entity);

                // 13.存储文件夹 是否存在
                File file = new File(filePath);
                if( !file.exists() ){
                    file.mkdirs();
                }

                // 14.文件全路径名
                fileAbsPath = filePath + File.separator + fileName;

                // 15.创建文件输出流 写出
                bos = new BufferedOutputStream(new FileOutputStream(fileAbsPath));
                bos.write(bytes,0 ,bytes.length);
                bos.flush();
            } else {
                System.out.println(url + " --请求File文件返回:code==> " + response.getStatusLine().getStatusCode());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != bos){
                try {
                    bos.close();
                } catch (IOException e) {
                    System.out.println(fileAbsPath + " --写入本地关流失败");
                }
            }
            if(null != response){
                try {
                    response.close();
                } catch (IOException e) {
                    System.out.println(url + " --响应response关闭失败");
                }
            }
            if(null != httpClient){
                try {
                    httpClient.close();
                } catch (IOException e) {
                    System.out.println(url + " --请求客户端关闭失败");
                }
            }
        }

    }



}
